package cn.tedu.csmall.passport.service.impl;

import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.csmall.passport.pojo.param.AdminUpdateInfoParam;
import cn.tedu.csmall.passport.pojo.param.AdminUpdatePasswordParam;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.csmall.passport.pojo.vo.PageData;
import cn.tedu.csmall.passport.ex.ServiceException;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.pojo.param.AdminAddNewParam;
import cn.tedu.csmall.passport.pojo.param.AdminLoginInfoParam;
import cn.tedu.csmall.passport.security.AdminDetails;
import cn.tedu.csmall.passport.service.IAdminService;
import cn.tedu.csmall.passport.util.PageInfoToPageDataConverter;
import cn.tedu.csmall.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    @Value("${csmall.jwt.secret-key}")
    private String secretKey;
    @Value("${csmall.jwt.duration-in-minute}")
    private Long durationInMinute;

    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private AdminRoleMapper adminRoleMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;

/*    @Autowired
    private AdminUpdatePasswordParam adminUpdatePasswordParam;*/


    @Override
    //添加管理员
    public void addNew(AdminAddNewParam adminAddNewParam) {


/*        log.debug("开始处理【添加管理员】的业务，参数：{}", adminAddNewParam);
        // 检查管理员用户名是否被占用，如果被占用，则抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", adminAddNewParam.getUsername());
        int countByUsername = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员用户名统计匹配的管理员数量，结果：{}", countByUsername);
        if (countByUsername > 0) {
            String message = "添加管理员失败，用户名已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // TODO 检查管理员手机号码是否被占用，如果被占用，则抛出异常
        // TODO 检查管理员电子邮箱是否被占用，如果被占用，则抛出异常

        // 将管理员数据写入到数据库中
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewParam, admin);
        admin.setLastLoginIp(null);
        admin.setLoginCount(0);
        admin.setGmtLastLogin(null);
        admin.setGmtCreate(LocalDateTime.now());
        admin.setGmtModified(LocalDateTime.now());
        int rows = adminMapper.insert(admin);
        if (rows != 1) {
            String message = "添加管理员失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.debug("将新的管理员数据插入到数据库，完成！");

        //将管理员与角色关联数据写入到数据库
        Long[] roleIds = adminAddNewParam.getRoleIds();
        AdminRole[] adminRoleList = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < adminRoleList.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoleList[i] = adminRole;
        }
        rows = adminRoleMapper.insertBatch(adminRoleList);
        if (rows != adminRoleList.length) {
            String message = "添加管理员失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.debug("将新的管理员与角色的关联数据插入到数据库，完成！");


    }*/
        log.debug("开始处理【添加管理员】的业务，参数：{}", adminAddNewParam);
        // 检查管理员用户名是否被占用，如果被占用，则抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", adminAddNewParam.getUsername());
        int countByUsername = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员用户名统计匹配的管理员数量，结果：{}", countByUsername);
        if (countByUsername > 0) {
            String message = "添加管理员失败，用户名已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 检查管理员手机号码是否被占用，如果被占用，则抛出异常
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", adminAddNewParam.getPhone());
        int countByPhoneNumber = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员手机号码统计匹配的管理员数量，结果：{}", countByPhoneNumber);
        if (countByPhoneNumber > 0) {
            String message = "添加管理员失败，手机号码已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 检查管理员电子邮箱是否被占用，如果被占用，则抛出异常
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", adminAddNewParam.getEmail());
        int countByEmail = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员电子邮箱统计匹配的管理员数量，结果：{}", countByEmail);
        if (countByEmail > 0) {
            String message = "添加管理员失败，电子邮箱已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 将管理员数据写入到数据库中
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewParam, admin);

        // 获取原密码并加密存储
        String plainTextPassword = admin.getPassword();
        String encodedPassword = passwordEncoder.encode(plainTextPassword);
        admin.setPassword(encodedPassword);

        admin.setLastLoginIp(null);
        admin.setLoginCount(0);
        admin.setGmtLastLogin(null);
        admin.setGmtCreate(LocalDateTime.now());
        admin.setGmtModified(LocalDateTime.now());
        int rows = adminMapper.insert(admin);
        if (rows != 1) {
            String message = "添加管理员失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.debug("将新的管理员数据插入到数据库，完成！");

        //将管理员与角色关联数据写入到数据库
        Long[] roleIds = adminAddNewParam.getRoleIds();
        AdminRole[] adminRoleList = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < adminRoleList.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoleList[i] = adminRole;
        }
        rows = adminRoleMapper.insertBatch(adminRoleList);
        if (rows != adminRoleList.length) {
            String message = "添加管理员失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.debug("将新的管理员与角色的关联数据插入到数据库，完成！");
    }


    @Override
    //管理员登录
    public String login(AdminLoginInfoParam adminLoginInfoParam) {
        log.debug("开始处理【管理员登录】的业务，参数：{}", adminLoginInfoParam);
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginInfoParam.getUsername(),
                adminLoginInfoParam.getPassword());
        // 执行认证，并获取认证结果
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.debug("验证登录完成！认证结果:{}", authenticateResult);

        //从认证结果中取出所需的数据
        Object principal = authenticateResult.getPrincipal();
        AdminDetails adminDetails = (AdminDetails) principal;
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();


        //生成JWT
        //String secretKey = "sjdhdkadhadhaHJDALKSJ2319871HKHKHASKjdadadja";
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", adminDetails.getId());
        claims.put("username", adminDetails.getUsername());
        claims.put("authoritiesJsonString", JSON.toJSONString(authorities));
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + durationInMinute * 1000 * 60))
                // Verify Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                // 生成
                .compact();
        log.debug("生成了此管理员的信息对应的JWT：{}", jwt);
        return jwt;

        /*//  ===== 使用JWT后不再需要以下2行代码 =====
        将认证结果存入到SecurityContext中
        SecurityContext securityContext = SecurityContextHolder.getContext();

        securityContext.setAuthentication(authenticateResult);*/
    }


    @Override
    //根据ID删除管理员密码
    public void delete(Long id) {

        log.debug("开始处理【删除管理员密码】的业务,参数:{}", id);
        // 检查管理员是否存在，如果不存在，则抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        int countById = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员ID统计匹配的管理员数量，结果：{}", countById);
        if (countById == 0) {
            String message = "删除管理员密码失败，管理员数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        // 检查是否有Role关联到了此管理员，如果存在，则抛出异常
        QueryWrapper<AdminRole> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.eq("admin_id", id);
        int countByAdminRoleId = adminRoleMapper.selectCount(queryWrapper4);
        log.debug("根据管理员ID统计匹配的role_id数量，结果：{}", countByAdminRoleId);

        int rows = adminMapper.deleteById(id);
        if (rows != 1) {
            String message = "删除管理员失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        //删除admin_role表中admin_id
        rows = adminRoleMapper.delByAdminId(id);
        if (rows != 1) {
            String message = "删除管理员失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }

    @Override
    //根据ID 查看管理员详情
    public AdminStandardVO getStandardById(Long id) {
        log.debug("开始处理【根据ID查询管理员详情】的业务，参数：{}", id);
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null) {
            String message = "查询管理员详情失败，管理员数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        return queryResult;
    }

    @Override
    //查询管理员页码数量
    public PageData<AdminListItemVO> list(Integer pageNum) {
        Integer pageSize = 5;
        return list(pageNum, pageSize);
    }

    @Override
    //查询管理员列表
    public PageData<AdminListItemVO> list(Integer pageNum, Integer pageSize) {
        log.debug("开始处理【查询管理员列表】的业务,页码:{},每页记录数:{}", pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<AdminListItemVO> list = adminMapper.list();
        PageInfo<AdminListItemVO> pageInfo = new PageInfo<>(list);
        PageData<AdminListItemVO> pageData = PageInfoToPageDataConverter.covert(pageInfo);
        log.debug("查询完成,即将返回{}", pageData);

        return pageData;
    }

    @Override
    //修改管理员密码
    public void updatePasswordById(Long id, AdminUpdatePasswordParam adminUpdatePasswordParam) {

        log.debug("开始处理【修改管理员密码】的业务,参数:{}", id);
        // 检查管理员是否存在，如果不存在，则抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        int countById = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员ID统计匹配的管理员数量，结果：{}", countById);
        if (countById == 0) {
            String message = "修改管理员密码失败，管理员数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 修改管理员密码
        Admin adminToUpdatePassword = new Admin();
        adminToUpdatePassword.setId(id);
        // 获取原密码并加密存储
        String plainTextPassword = adminUpdatePasswordParam.getPassword();
        String encodedPassword = passwordEncoder.encode(plainTextPassword);
        adminToUpdatePassword.setPassword(encodedPassword);
        // 执行更新操作
        int rows = adminMapper.updateById(adminToUpdatePassword);
        if (rows != 1) {
            String message = "修改管理员密码失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    //修改管理员的基本信息
    public void updateInfoById(Long id, AdminUpdateInfoParam adminUpdateInfoParam) {
        log.debug("开始处理【修改管理员密码】的业务,参数:{}", id);
        // 检查管理员是否存在，如果不存在，则抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        int countById = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员ID统计匹配的管理员数量，结果：{}", countById);
        if (countById == 0) {
            String message = "修改管理员密码失败，管理员数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 查询除当前管理员外是否有使用新手机号码的账号
        QueryWrapper<Admin> phoneConflictWrapper = new QueryWrapper<>();
        phoneConflictWrapper.ne("id", id);
        phoneConflictWrapper.eq("phone", adminUpdateInfoParam.getPhone());
        int phoneConflictCount = adminMapper.selectCount(phoneConflictWrapper);
        log.debug("查询手机号码冲突数量，结果：{}", phoneConflictCount);
        if (phoneConflictCount > 0) {
            String message = "修改管理员信息失败，已存在相同的手机号码！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_BAD_REQUEST, message);
        }

        // 查询除当前管理员外是否有使用新电子邮箱的账号
        QueryWrapper<Admin> emailConflictWrapper = new QueryWrapper<>();
        emailConflictWrapper.ne("id", id);
        emailConflictWrapper.eq("email", adminUpdateInfoParam.getEmail());
        int emailConflictCount = adminMapper.selectCount(emailConflictWrapper);
        log.debug("查询电子邮箱冲突数量，结果：{}", emailConflictCount);
        if (emailConflictCount > 0) {
            String message = "修改管理员信息失败，已存在相同的电子邮箱地址！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_BAD_REQUEST, message);
        }

        // 创建待更新的Admin对象，并设置属性值
        Admin adminToUpdate = new Admin();
        adminToUpdate.setId(id);
        adminToUpdate.setUsername(adminUpdateInfoParam.getUsername());
        adminToUpdate.setNickname(adminUpdateInfoParam.getNickname());
        adminToUpdate.setAvatar(adminUpdateInfoParam.getAvatar());
        adminToUpdate.setPhone(adminUpdateInfoParam.getPhone());
        adminToUpdate.setEmail(adminUpdateInfoParam.getEmail());
        adminToUpdate.setDescription(adminUpdateInfoParam.getDescription());
        adminToUpdate.setEnable(adminUpdateInfoParam.getEnable());

        // 执行更新操作
        int updateCount = adminMapper.updateById(adminToUpdate);
        log.debug("更新管理员信息结果：{}", updateCount);
        if (updateCount != 1) {
            String message = "修改管理员信息失败！";
            log.error(message);
        }
    }

}